
// Pila de matrices
var pila = new Array();
// Matriz identidad
var identidad=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];
//ancho y alto de la matriz
var N=4,M=4;
//Contexto del canvas
var context;

//Multiplicación de matrices: Multiplica la matriz recibida con
//la matriz de la cima de la pila
function multMatriz(matriz2) {
	var matriz1=pila.pop();
	var res, matriz3=new Array();
	for (i=0; i<N; i++) {
		matriz3[i]=new Array();
		for (j=0; j<M; j++) {
			res=0;
			for (k=0; k<M; k++) {
				res += matriz1[i][k] * matriz2[k][j];
			}
			matriz3[i][j]=res;
		}
	}
	pila.push(matriz3);
} 

//Aplica la matriz a un punto de M dimensiones y retorna el
//nuevo punto
function transformPointLG(punto) {
	var matriz = pila[pila.length-1];
	var res, tpoint=new Array();
	for (var i=0; i<N; i++) {
		res=0;
		for (var k=0; k<M; k++) {
			res += matriz[i][k] * punto[k];
		}
		tpoint[i]=res;		
	}
	//Normalizando
	for (var i=0; i<N; i++)
		tpoint[i] /= tpoint[N-1];
	return tpoint;
}

//Inicializa la pila y demas variabled de la librería
//Llamar esta función antes de empezar a utilizar los métodos
function initLG(contexto) {
	pila.push(identidad);
	context = contexto;
}

function setCoordinatesLG(x0,y0,sx,sy) {
	context.translate(x0,y0);
	context.scale(sx,sy);
}

//Esta función le saca una copia a la matriz que está en la
//cima de la pila e inserta esta copia en la cima de la pila
function pushLG() {
	var m1 = pila.pop();
	var m2 = new Array();
	for (i=0; i<N; i++) {
		m2[i]=new Array();
		for (j=0; j<M; j++) {
			m2[i][j] = m1[i][j];
		}
	}
	pila.push(m1);
	pila.push(m2);
}

//Esta función elimina la matriz que esta en la cima de la pila
//y la retorna como resultado
function popLG() {
	return pila.pop();
}

//Imprime la matriz en forma de tabla
function printMatrix(matriz) {
	document.write("<table>");
	for (i=0; i<N; i++) {
		document.write("<tr>");
		for (j=0; j<M; j++) {
			document.write("<td>" + matriz[i][j] + "</td>");
		}
		document.write("</ tr>");
	}
	document.write("</table>");
}

//Transformaciones

function rotz(angle) {
	var mat1 = [[Math.cos(angle),-Math.sin(angle),0,0],[Math.sin(angle),Math.cos(angle),0,0],[0,0,1,0],[0,0,0,1]];
	multMatriz(mat1);	
}

function roty(angle) {
	var mat1 = [[Math.cos(angle),0,-Math.sin(angle),0],[0,1,0,0],[Math.sin(angle),0,Math.cos(angle),0],[0,0,0,1]];
	multMatriz(mat1);	
}

function rotx(angle) {
	var mat1 = [[1,0,0,0],[0,Math.cos(angle),-Math.sin(angle),0],[0,Math.sin(angle),Math.cos(angle),0],[0,0,0,1]];
	multMatriz(mat1);	
}

function escalarLG(sx,sy,sz) {
	var mat1=[[sx,0,0,0],[0,sy,0,0],[0,0,sz,0],[0,0,0,1]];
	multMatriz(mat1);
}

function transladarLG(dx,dy,dz) {
	var mat1=[[1,0,0,dx],[0,1,0,dy],[0,0,1,dz],[0,0,0,1]];
	multMatriz(mat1);
}

//Matriz de proyección, cullo plano de proyección es el plano
//x,y y el punto focal se encuentra en (0,0,d)
function proyeccionLG(d) {
	var mat1=[[d,0,0,0],[0,d,0,0],[0,0,0,0],[0,0,-1,d]];
	multMatriz(mat1);
}


//Funciones gráficas primitivas

//Grafica en un plano un polígono dado por los puntos, y aplica
//la matriz de transformación; points en un arreglo de puntos
function planePolyLG(points) {
	context.beginPath();
	var p1 = transformPointLG(points[0]);
	context.moveTo(p1[0],p1[1]);
	for (var i=1; i<points.length; i++) {
		var tpoint = transformPointLG(points[i]);
		context.lineTo(tpoint[0],tpoint[1]);
	}
	context.lineTo(p1[0],p1[1]);
	context.closePath();
	context.stroke();
}

function wireCubeLG() {
	planePolyLG([[1,1,1,1],[1,-1,1,1],[-1,-1,1,1],[-1,1,1,1]]);	
	planePolyLG([[1,1,-1,1],[1,-1,-1,1],[-1,-1,-1,1],[-1,1,-1,1]]);
	planePolyLG([[1,1,1,1],[-1,1,1,1],[-1,1,-1,1],[1,1,-1,1]]);
	planePolyLG([[1,-1,1,1],[-1,-1,1,1],[-1,-1,-1,1],[1,-1,-1,1]]);
	planePolyLG([[1,1,1,1],[1,-1,1,1],[1,-1,-1,1],[1,1,-1,1]]);
	planePolyLG([[-1,1,1,1],[-1,-1,1,1],[-1,-1,-1,1],[-1,1,-1,1]]);
}

